package at.brandl.wwi;

import java.util.ArrayList;
import java.util.List;

import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.format.DateUtils;
import android.util.Log;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;

public class WhereWasIMapActivity extends MapActivity {

	private static final int NA = -1;
	private static final String TAG = "mapActivity";
	private List<Overlay> mapOverlays;
	private Drawable drawable;
	private WhereWasIOverlay itemizedOverlay;
	private MapView mapView;
	private long startTime;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		startTime = System.currentTimeMillis();
		
		debugTimeStamp("onCreate begin");
		super.onCreate(savedInstanceState);
		setContentView(R.layout.map);

		mapView = (MapView) findViewById(R.id.mapview);
		mapOverlays = mapView.getOverlays();
		drawable = getResources().getDrawable(R.drawable.android);
		itemizedOverlay = new WhereWasIOverlay(drawable, this);

		debugTimeStamp("get old data");
		ConfigData data = (ConfigData) getLastNonConfigurationInstance();
		List<OverlayItem> items;

		if (data == null) {
			debugTimeStamp("no old data found");
			items = getItemsFromBundleOrIntent(savedInstanceState);
		} else {
			debugTimeStamp("old data found");
			items = data.items;
		}

		debugTimeStamp("add items to overlay");
		for (OverlayItem item : items) {
			itemizedOverlay.addOverlayItem(item);
		}

		if (itemizedOverlay.size() > 0) {
			debugTimeStamp("populate");
			itemizedOverlay.populateOverlay();
			debugTimeStamp("add overlay to map");
			mapOverlays.add(itemizedOverlay);
			
			debugTimeStamp("zoom to map");
			MapController controller = mapView.getController();
			if (data == null) {
				controller.zoomToSpan(itemizedOverlay.getLatSpanE6(),
						itemizedOverlay.getLonSpanE6());
				controller.setCenter(getCenter(items));
			} else {
				controller.setZoom(data.zoomLevel);
				controller.setCenter(data.center);
			}
		}
		debugTimeStamp("onCreate end");
	}

	private void debugTimeStamp(String message) {
		long duration = System.currentTimeMillis() - startTime;
		Log.d(TAG, new StringBuilder(message).append(": ").append(duration).append("ms").toString());
	}

	private GeoPoint getCenter(List<OverlayItem> items) {
		int minLat = Integer.MAX_VALUE;
		int maxLat = Integer.MIN_VALUE;
		int minLong = Integer.MAX_VALUE;
		int maxLong = Integer.MIN_VALUE;
		for (OverlayItem item : items) {
			GeoPoint point = item.getPoint();
			int latitude = point.getLatitudeE6();
			int longitude = point.getLongitudeE6();
			minLat = Math.min(latitude, minLat);
			maxLat = Math.max(latitude, maxLat);
			minLong = Math.min(longitude, minLong);
			maxLong = Math.max(longitude, maxLong);
		}
		return new GeoPoint((minLat + maxLat) / 2, (minLong + maxLong) / 2);
	}

	private List<OverlayItem> getItemsFromBundleOrIntent(
			Bundle savedInstanceState) {
		debugTimeStamp("get rowId, starttime, endtime");
		Long rowId = (savedInstanceState == null) ? null
				: (Long) savedInstanceState
						.getSerializable(WhereWasIDbAdapter.KEY_ID);

		Long startTime = null;
		Long endTime = null;
		if (rowId == null) {
			Bundle extras = getIntent().getExtras();
			if (extras != null) {
				long row = extras.getLong(WhereWasIDbAdapter.KEY_ID, NA);
				rowId = row == NA ? null : Long.valueOf(row);

				if (rowId == null) {
					long start = extras.getLong(
							WhereWasISelectionActivity.START, NA);
					startTime = start == NA ? null : Long.valueOf(start);
					long end = extras.getLong(WhereWasISelectionActivity.END,
							NA);
					endTime = end == NA ? null : Long.valueOf(end);
				}
			}
		}

		debugTimeStamp("get items from db");
		List<OverlayItem> items = new ArrayList<OverlayItem>();
		if (rowId != null || (startTime != null && endTime != null)) {
			items.addAll(getItemsFromDb(rowId, startTime, endTime));
		}
		return items;
	}

	private List<OverlayItem> getItemsFromDb(Long rowId, Long startTime,
			Long endTime) {
		List<OverlayItem> items = new ArrayList<OverlayItem>();
		WhereWasIDbAdapter dbHelper = new WhereWasIDbAdapter(this);
		dbHelper.open();

		Cursor c;
		if (rowId != null) {
			c = dbHelper.getPoint(rowId.longValue());
		} else {
			c = dbHelper.getPointsBetween(
					WhereWasIPoint.convertToMinutes(startTime.longValue()),
					WhereWasIPoint.convertToMinutes(endTime.longValue()));
		}
		startManagingCursor(c);

		while (c.moveToNext()) {
			OverlayItem item = createItem(c);
			items.add(item);
		}

		dbHelper.close();
		return items;
	}

	private OverlayItem createItem(Cursor c) {
		GeoPoint geopoint = new GeoPoint(c.getInt(c
				.getColumnIndex(WhereWasIDbAdapter.KEY_LATITUDE)), c.getInt(c
				.getColumnIndex(WhereWasIDbAdapter.KEY_LONGITUDE)));
		String text = new StringBuilder(getTimeStr(c))
				.append(", ")
				.append(c.getInt(c
						.getColumnIndex(WhereWasIDbAdapter.KEY_ACCURACY)))
				.append("m").toString();
		OverlayItem item = new OverlayItem(geopoint, "", text);
		return item;
	}

	private String getTimeStr(Cursor c) {
		return DateUtils.formatDateTime(getApplicationContext(), WhereWasIPoint
				.convertToTimeMillis(c.getInt(c
						.getColumnIndex(WhereWasIDbAdapter.KEY_TIME))),
				DateUtils.FORMAT_24HOUR | DateUtils.FORMAT_SHOW_TIME
						| DateUtils.FORMAT_SHOW_DATE);
	}

	@Override
	public Object onRetainNonConfigurationInstance() {
		ConfigData data = new ConfigData();
		int length = itemizedOverlay.size();

		data.items = new ArrayList<OverlayItem>(length);
		for (int i = 0; i < length; i++) {
			data.items.add(itemizedOverlay.getItem(i));
		}
		data.zoomLevel = mapView.getZoomLevel();
		data.center = mapView.getMapCenter();
		return data;
	}

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}

	private static class ConfigData {
		public GeoPoint center;
		private List<OverlayItem> items;
		private int zoomLevel;
	}
}
